package com.lion.seaman.orm.service.impl;

import com.lion.seaman.common.tools.GenericsTools;
import com.lion.seaman.orm.dao.BaseDAO;
import com.lion.seaman.orm.jpa.LionSpecification;
import com.lion.seaman.orm.jpa.SearchFilter;
import com.lion.seaman.orm.service.BaseService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;

import java.io.Serializable;
import java.util.*;

public class BaseServiceImpl<T, ID extends Serializable> implements BaseService<T, ID> {
    public BaseDAO<T, ID> baseDAO;
    T entity;
    Class<ID> id;

    public BaseServiceImpl() {
        this.entity = instanceAnnotationObject();
        this.id = instanceAnnotationID();
    }

    @SuppressWarnings("unchecked")
    public T instanceAnnotationObject() {
        try {
            return (T) GenericsTools.getSuperClassGenricType(getClass(), 0)
                    .newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public Class<ID> instanceAnnotationID() {
        try {
            return GenericsTools.getSuperClassGenricType(getClass(), 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Page<T> findPagingByIdASC(int pageNumber, int pageSize) {
        return findPaging(pageNumber, pageSize, null, Direction.ASC, "id");
    }

    public Page<T> findPagingByIdDESC(int pageNumber, int pageSize) {
        return findPaging(pageNumber, pageSize, null, Direction.DESC, "id");
    }

    public Page<T> findPagingSearchLikeByIdDESC(int pageNumber, int pageSize, String searchKey, Object searchValue) {
        Map<String, Object> searchParams = new HashMap<String, Object>();
        searchParams.put(searchKey, searchValue);
        return findPaging(pageNumber, pageSize, searchParams, Direction.DESC, "id");
    }

    public Page<T> findPaging(int pageNumber, int pageSize, Map<String, Object> searchParams,
                              Direction direction, List<String> properties) {
        PageRequest pageRequest = buildPageRequest(pageNumber, pageSize, direction, properties);
        Specification<T> spec = buildSpecification(searchParams);
        return baseDAO.findAll(spec, pageRequest);
    }

    public Page<T> findPaging(int pageNumber, int pageSize, Map<String, Object> searchParams,
                              Direction direction, String... properties) {
        PageRequest pageRequest = buildPageRequest(pageNumber, pageSize, direction, properties);
        Specification<T> spec = buildSpecification(searchParams);
        return baseDAO.findAll(spec, pageRequest);
    }

    public List<T> findAll(Map<String, Object> searchParams) {
        return findAll(searchParams, null);
    }

    public List<T> findAll(Map<String, Object> searchParams, Sort sort) {
        Specification<T> spec = buildSpecification(searchParams);
        if (sort != null) {
            return baseDAO.findAll(spec, sort);
        } else {
            return baseDAO.findAll(spec);
        }
    }

    public List<T> findAll() {
        return baseDAO.findAll();
    }

    public List<T> findByProperty(String property, Object value, Sort sort) {
        Map<String, Object> searchParams = new HashMap<String, Object>();
        searchParams.put(property, value);
        return findAll(searchParams, sort);
    }

    public List<T> findByProperty(String property, Object value) {
        return findByProperty(property, value, null);
    }

    /**
     * 创建分页请求.
     */
    private PageRequest buildPageRequest(int pageNumber, int pagzSize, Direction direction, List<String> properties) {
        Sort sort = new Sort(direction, properties);
        return new PageRequest(pageNumber - 1, pagzSize, sort);
    }

    /**
     * 创建分页请求.
     */
    private PageRequest buildPageRequest(int pageNumber, int pagzSize, Direction direction, String... properties) {
        if (direction != null && properties != null) {
            Sort sort = new Sort(direction, properties);
            return new PageRequest(pageNumber - 1, pagzSize, sort);
        } else {
            return new PageRequest(pageNumber - 1, pagzSize);
        }
    }

    /**
     * 创建动态查询条件组合.
     */
    protected Specification<T> buildSpecification(Map<String, Object> searchParams) {
        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
        Specification<T> spec = (Specification<T>) new LionSpecification<T>(filters.values());
        return spec;
    }

    @Override
    public T getById(ID id) {
        return baseDAO.getById(id);
    }

    @Override
    public T saveOrUpdate(T entity) {
        return baseDAO.saveAndFlush(entity);
    }

    @Override
    public void delete(T entity) {
        baseDAO.delete(entity);
    }

    @Override
    public void delete(ID id) {
        baseDAO.delete(id);
    }

    @Override
    public void delete(Iterable<T> entites) {
        baseDAO.delete(entites);
    }

    @Override
    public void deleteInBatch(Iterable<T> entites) {
        baseDAO.deleteInBatch(entites);
    }

    @Override
    public boolean exists(ID id) {
        return baseDAO.exists(id);
    }

    public T getEntity() {
        return entity;
    }

    @Override
    public void deleteByIdIn(Collection<ID> idList) {
        List<T> dbList = baseDAO.findAll(idList);
        baseDAO.delete(dbList);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void deleteByIdString(String idString, String splitReg) {
        List<ID> idList = new ArrayList<ID>();
        String[] idArr = idString.split(splitReg);
        if (this.id == String.class) {
            for (int i = 0; i < idArr.length; i++) {
                ID pk = (ID) idArr[i];
                idList.add(pk);
            }
        } else if (this.id == Long.class) {
            for (int i = 0; i < idArr.length; i++) {
                ID pk = (ID) Long.valueOf(idArr[i]);
                idList.add(pk);
            }
        } else if (this.id == Integer.class) {
            for (int i = 0; i < idArr.length; i++) {
                ID pk = (ID) Integer.valueOf(idArr[i]);
                idList.add(pk);
            }
        }

        if (!idList.isEmpty()) {
            deleteByIdIn(idList);
        }
    }

}